#include "huawei_handle.h"
#include <vector>
#include <algorithm>
#include <map>
#include <syslog.h>

void huawei_process_json_work_file(const char *json_work_file, json_t **json_config)
{
    json_error_t error;

    *json_config = json_load_file(json_work_file, JSON_DECODE_ANY, &error);
    if (!*json_config)
    {
        fprintf(stderr,
                "Failed to parse JSON config %s [%s at line %d column %d]\n",
                json_work_file, error.text, error.line, error.column);
        syslog(LOG_ERR, "Failed to parse JSON config %s [%s at line %d column %d]", json_work_file, error.text, error.line, error.column);
        exit(1);
    }
}

off_t huawei_get_length(json_t *json_config)
{
    json_t *sectorOfBlock = json_object_get(json_config, "sectorOfBlock");
    json_t *bitNum = json_object_get(json_config, "bitNum");
    off_t len = json_integer_value(sectorOfBlock) * 512 * json_integer_value(bitNum);
    return len;
}

bool huawei_find_data_region(int fd, off_t offset, off_t& start, off_t& end) {
    start = lseek(fd, offset, SEEK_DATA);
    if (start == static_cast<off_t>(-1)) {
        if (errno == ENXIO) {
            return false;
        } else {
            syslog(LOG_ERR, "lseek SEEK_DATA failed at offset %lld: %s", static_cast<long long>(offset), strerror(errno));
            return false;
        }
    }

    end = lseek(fd, start, SEEK_HOLE);
    if (end == static_cast<off_t>(-1)) {
        if (errno == ENXIO) {
            end = lseek(fd, 0, SEEK_END);
            if (end == static_cast<off_t>(-1)) {
                syslog(LOG_ERR, "lseek SEEK_END failed: %s", strerror(errno));
                return false;
            }
        } else {
            syslog(LOG_ERR, "lseek SEEK_HOLE failed at offset %lld: %s", static_cast<long long>(start), strerror(errno));
            return false;
        }
    }

    return true;
}

struct huawei_DataSegment {
    off_t start;
    off_t end;
    size_t file_index;
};

void huawei_read_disk_data(std::vector<int> &fd_vector, char *buf, off_t offset, size_t rsize)
{
    if (fd_vector.empty())
    {
        memset(buf, 0, rsize);
        return;
    }

    if(fd_vector.size() == 1)
    {
        ssize_t n = pread(fd_vector[0], buf, rsize, offset);
        if (n < 0) {
            syslog(LOG_ERR, "pread failed for single fd: %s", strerror(errno));
            memset(buf, 0, rsize);
        }
    }
    else
    {
        memset(buf, 0, rsize);
        off_t cur_offset = offset;
        off_t end_offset = cur_offset + (off_t)rsize;
        while (cur_offset < end_offset)
        {
            std::vector<huawei_DataSegment> segments;
            for (size_t i = 0; i < fd_vector.size(); i++)
            {
                off_t seg_start, seg_end;
                if (huawei_find_data_region(fd_vector[i], cur_offset, seg_start, seg_end)) {
                    seg_start = std::max(seg_start, cur_offset);
                    seg_end = std::min(seg_end, end_offset);
                    if (seg_start < seg_end) {
                        segments.push_back({seg_start, seg_end, i});
                    }
                }
            }
            if (segments.empty()) {
                break;
            }
            std::sort(segments.begin(), segments.end(),
                [](const huawei_DataSegment& a, const huawei_DataSegment& b) {
                    if (a.start == b.start) return a.file_index < b.file_index;
                    return a.start < b.start;
                });
            // 遍历所有数据段，依次读取
            for (const auto& seg : segments) {
                if (seg.start >= end_offset) continue;

                size_t buf_pos = static_cast<size_t>(seg.start - offset);
                size_t read_size = static_cast<size_t>(seg.end - seg.start);

                if (read_size == 0) continue;

                ssize_t n = pread(fd_vector[seg.file_index],
                                buf + buf_pos,
                                read_size,
                                seg.start);
                if (n < 0) {
                    syslog(LOG_ERR, "pread failed for fd[%zu] at %lld: %s",
                        seg.file_index,
                        static_cast<long long>(seg.start),
                        strerror(errno));
                }
            }

            // 找出所有 segments 中最大的 end，作为下一轮的 cur_offset
            off_t max_end = cur_offset;
            for (const auto& seg : segments) {
                if (seg.end > max_end) {
                    max_end = seg.end;
                }
            }

            if (max_end <= cur_offset) {
                // 避免死循环
                cur_offset++;
            } else {
                cur_offset = max_end;
            }

            if (cur_offset > end_offset) {
                cur_offset = end_offset;
            }
        }
    }
}